package com.nulldev.util.io.nfs;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.EOFException;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

import com.nulldev.util.io.FileUtil;
import com.nulldev.util.io.nStreams.ByteArrayStream;
import com.nulldev.util.io.nStreams.nStream;
import com.nulldev.util.logging.Logger;
import com.nulldev.util.logging.LoggerFactory;
import com.nulldev.util.other.ByteUtils;

public class nFile {
	private static final Logger log = LoggerFactory.getLogger(true, true);	
	
	private volatile byte[] fileData;
	/**
	 * WARNING: This cannot be a length of 0! <br>
	 * 
	 * Format: <br>
	 * FILE_NAME;DATE_OF_CREATION;LAST_MODIFICATION;ENCRYPTED=[1/0];COMPRESSED=[1/0];ENCRYPTION_TYPE=[-1 -> type]
	 */
	private volatile byte[] fileMetadata = new byte[] {'\u0000'};
	
	private String fileName;
	
	public nFile(final String fileName) {
		this.fileName = fileName;
		this.fileData = new byte[] {};
		this.fileMetadata = (fileName + ";").getBytes();
	}
	
	public nFile(final File f) throws IOException {
		this(new FileInputStream(f));
		this.fileName = f.getName();
	}
	
	public nFile(final InputStream is) throws IOException {
		if (!(is instanceof FileInputStream)) {
			this.fileName = "New File.nf";
		}
		this.fileData = FileUtil.toByteArray(is);
		is.close();
		//THIS SHOULDN'T BE HERE
//		this.fileData = new byte[] {};
//		final DataInputStream dis = new DataInputStream(is);
//		final long header0 = dis.readLong();
//		if (header0 != nFileSystem.nFS_FILE_HEADER_ID) {
//			log.info("Assuming this is a new file, reading bytes...");
//			//TODO: Assume as a new file, read bytes and finish
//			//throw new UnsupportedOperationException("Attempted to read an incompatible nFile!");
//			this.fileData = FileUtil.toByteArray(dis);
//			dis.close();
//			return;
//		}
//		final ArrayList<Byte> headerValues = new ArrayList<Byte>();
//		byte b0;
//		while ((b0 = dis.readByte()) != nFileSystem.END_OF_HEADERS_MAGIC_LONG) {
//			headerValues.add(b0);
//		}
//		final byte[] metadata = ByteUtils.fromList(headerValues);
//		//TODO: Implement metadata handling
//		this.fileMetadata = metadata;
//		int read = 0;
//		while (true) {
//			try {
//				final byte r = dis.readByte();
//				if (r == nFileSystem.nFS_FILE_SEPERATOR) {
//					break;
//				}
//				this.fileData[read] = r;
//				read++;
//			}catch (EOFException eof) {
//				break;
//			}catch (Exception e) {
//				e.printStackTrace();
//			}
//		}
//		dis.close();
	}
	
	public nFile(final String fileName, final byte[] data) {
		this.fileData = data;
		this.fileName = fileName;
		this.fileMetadata = (fileName + ";").getBytes();
	}
	
	public long length() {
		return this.fileData.length;
	}
	
	public String getName() {
		return this.fileName;
	}
	
	public byte[] getMetadataBytes() {
		return this.fileMetadata;
	}
	
	public byte[] getData() {
		return this.fileData;
	}
	
	public InputStream getInputStream() {
		return new ByteArrayInputStream(this.fileData);
	}
	
	/**
	 * Read only stream.
	 * @returns nStream
	 */
	public nStream getStream() {
		return new ByteArrayStream(this.fileData);
	}
	
	@Override
	public String toString() {
		return "nFile[fileName=" + this.fileName + ",length=" + this.length() + ",size=" + FileUtil.convertToStringRepresentation(this.length()) + "]";
	}

	public void setMetadata(final byte[] metadata) {
		this.fileMetadata = metadata;
	}

	public void setData(final byte[] data) {
		this.fileData = data;
	}

	public void setName(final String name) {
		this.fileName = name;
	}
}
